package ro.isdc.navigator.component.view;

import java.util.Iterator;
import java.util.List;

import org.apache.wicket.markup.html.navigation.paging.IPageable;
import org.apache.wicket.markup.repeater.RefreshingView;
import org.apache.wicket.model.AbstractReadOnlyModel;
import org.apache.wicket.model.IModel;

import ro.isdc.navigator.IPagesNavigator;
import ro.isdc.navigator.Page;
import ro.isdc.navigator.exceptions.SearchLimitExceededException;

/**
 * Wicket component that ensures pagination using a IPagesNavigator component.
 * 
 * @author Andrei Chirila / ISDC! Romania
 * @version 1.0
 * @date Jul 17, 2009
 * @param <T>
 */
public abstract class AbstractPageNavigatorView<T> extends RefreshingView<T>
    implements IPageable {

  /**
   * Generated Serial Version UID
   */
  private static final long serialVersionUID = 7270799042747181999L;

  /**
   * A pages navigator interface reference.
   */
  private IPagesNavigator<T> navigator;

  /**
   * Keeps the current page state.
   */
  private int currentPage;

  /**
   * Constructor
   * 
   * @param id
   *          the Wicket id
   * @param navigator
   *          a IPagesNavigator implementation reference
   */
  public AbstractPageNavigatorView(final String id,
      final IPagesNavigator<T> navigator) {
    super(id);
    this.navigator = navigator;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  protected Iterator<IModel<T>> getItemModels() {
    Iterator<IModel<T>> models = null;
    try {
      Page<T> page = navigator.getPage(currentPage + 1);
      models = getItemModels(page.getResults(), page.getPageSize());
    } catch (SearchLimitExceededException e) {
      e.printStackTrace();
    }

    return models;
  }

  /**
   * Returns an iterator of models when given the list of elements and the
   * number of elements.
   * 
   * @param list
   *          the list of elements
   * @param count
   *          the number of elements
   * @return the model iterator
   */
  private Iterator<IModel<T>> getItemModels(final List<T> list, final int count) {
    return new ModelIterator<T>(list, count);
  }

  /**
   * Model iterator that iterates through Wicket models.
   * 
   * @author Andrei Chirila / ISDC! Romania
   * @version 1.0
   * @date Jul 17, 2009 
   * @param <T>
   */
  private static final class ModelIterator<T> implements Iterator<IModel<T>> {
    private final Iterator<? extends T> items;
    private final int max;
    private int index;

    /**
     * Constructor
     * 
     * @param list the list of elements
     * @param count the number of elements
     */
    public ModelIterator(final List<? extends T> list, final int count) {
      items = list.iterator();
      max = count;
    }

    /**
     * @see java.util.Iterator#remove()
     */
    public void remove() {
      throw new UnsupportedOperationException();
    }

    /**
     * @see java.util.Iterator#hasNext()
     */
    public boolean hasNext() {
      return items.hasNext() && (index < max);
    }

    /**
     * @see java.util.Iterator#next()
     */
    @SuppressWarnings("serial")
    public IModel<T> next() {
      index++;
      return new AbstractReadOnlyModel<T>() {

        @Override
        public T getObject() {
          return items.next();
        }
      };
    }
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public int getCurrentPage() {
    return currentPage;
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public int getPageCount() {
    return navigator.getPagesCount();
  }

  /**
   * {@inheritDoc}
   */
  @Override
  public void setCurrentPage(int page) {
    if (page < 0 || (page >= getPageCount() && getPageCount() > 0)) {
      throw new IndexOutOfBoundsException("argument [page]=" + page
          + ", must be 0<=page<" + getPageCount());
    }

    this.currentPage = page;
  }

}
